package com.xw.echo.core.cluster;

import com.xw.echo.core.annotation.AsyncInvoke;
import com.xw.echo.core.pool.ConnectPool;
import com.xw.echo.core.pool.ManagerConnectPool;
import com.xw.echo.core.protocol.MethodInvokData;
import com.xw.echo.core.trans.EchoTransPort;
import com.xw.echo.core.trans.TransPort;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ExecutionException;


/**
 * 集群客户端类，实现集群接口
 * 该类负责根据负载均衡策略选择服务器，并通过连接池管理连接
 */
public class ClusterClient implements Cluster {
    // 连接池管理器，用于获取和管理连接池
    private ManagerConnectPool managerConnectPool = ManagerConnectPool.getInstance();
    // 服务名称
    private String serviceName;


    /**
     * 构造函数，初始化服务名称和目标接口
     *
     * @param serviceName     服务名称

     */
    public ClusterClient(String serviceName) {
        this.serviceName = serviceName;
    }

    /**
     * 调用方法，根据负载均衡策略选择服务器并执行方法调用
     *
     *
     * @param methodInvokData 方法调用数据
     * @return 调用结果
     */
    @Override
    public Object invoke(String hostAndPort, MethodInvokData methodInvokData, Method method) {
        Map<String, ConnectPool> connectPoolsMap = managerConnectPool.getClusterMap(serviceName);
        ConnectPool connectPool = connectPoolsMap.get(hostAndPort);
        TransPort transPort = new EchoTransPort(connectPool);
        try {
            // parseMethodInvoker 要么返回 "DefaultInvoke"，要么返回异步调用产生的 CompletableFuture
            Object result = parseMethodInvoker(method, transPort, methodInvokData);

            // 如果不是异步调用（即返回的是 "DefaultInvoke"）
            if ("DefaultInvoke".equals(result)) {
                result = transPort.invoker(methodInvokData); // 执行同步调用
            }

            // 直接返回结果
            return result;

        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

    public Object parseMethodInvoker(Method method, TransPort transPort, MethodInvokData methodInvokData) throws InterruptedException {
        Annotation[] annotations = method.getAnnotations();
        for (Annotation annotation : annotations) {
            if (annotation instanceof AsyncInvoke) {
                return transPort.asyncInvoker(methodInvokData);
            }
        }
        return "DefaultInvoke";
    }


}
